package wallet

import (
	"fmt"
	"os"
	"io/ioutil"
	"log"
	"encoding/gob"
	"crypto/elliptic"
	"bytes"
)

// 一、（2）多个钱包
type Wallets struct {
	Wallets map[string]*Wallet
}

// 获取多个钱包
func NewWallets()(*Wallets,error)  {
	wallets := Wallets{}
	wallets.Wallets = make(map[string]*Wallet)

	err := wallets.LoadFromFile()

	return &wallets, err
}

// 创建钱包
func (ws *Wallets)CreateWallet()string  {
	wallet := NewWallet()
/*
	func Sprintf(format string, a ...interface{}) string
	Sprintf根据format参数生成格式化的字符串并返回该字符串。
*/
	address := fmt.Sprintf("%s",wallet.GetAddress())

	ws.Wallets[address] = wallet

	return address
}

// 获取多个地址
func (ws *Wallets)GetAddresses()[]string  {
	var  addresses []string

	for address := range ws.Wallets{
		addresses = append(addresses,address)
	}

	return addresses
}

// 七、（1）实现获取多个钱包
func NewWalltes()(*Wallets,error)  {
	wallts := Wallets{}
	wallts.Wallets = make(map[string]*Wallet)

	err := wallts.LoadFromFile()

	return &wallts,err
}

// 七、（2）文件中读取钱包
func (ws *Wallets)LoadFromFile()error  {
	if _,err := os.Stat(walletFile);os.IsNotExist(err) {
		return err
	}
	/*
		(1)ioutil
		该包实现了一些 I / O 实用程序功能。例如:ReadAll/ReadDir/ReadFile/TempDir/TempFile
		(2)func ReadFile(filename string) ([]byte, error)
		ReadFile 读取由文件名命名的文件并返回内容。一个成功的调用返回 err == nil，而不是 err == EOF 。
		由于 ReadFile 读取整个文件，因此它不会将来自 Read 的 EOF 视为要报告的错误。
	*/
	fileContent,err := ioutil.ReadFile(walletFile)// 读取文件
	if err != nil {
		log.Panic(err)
	}

	wallets := new(Wallets)// var wallets Wallets
	/*
		func Register(value interface{})
	Register记录value下层具体值的类型和其名称。该名称将用来识别发送或接受接口类型值时下层的具体类型。
	本函数只应在初始化时调用，如果类型和名字的映射不是一一对应的，会panic。
	*/
	gob.Register(elliptic.P256())
	/*
		(1)func NewDecoder(r io.Reader) *Decoder
		函数返回一个从r读取数据的*Decoder，如果r不满足io.ByteReader接口，则会包装r为bufio.Reader。
		(2)Type Reader struct{
		}
	Reader类型通过从一个[]byte读取数据，实现了io.Reader、io.Seeker、io.ReaderAt、io.WriterTo、
	io.ByteScanner、io.RuneScanner接口。

		(3)func NewReader(b []byte) *Reader
		NewReader创建一个从b读取数据的Reader。
	*/
	decoder := gob.NewDecoder(bytes.NewReader(fileContent))
	err = decoder.Decode(&wallets)
	if err != nil {
		log.Panic(err)
	}

	ws.Wallets = wallets.Wallets

	return nil
}

// 七、(3)获取钱包：通过地址获取钱包
func (ws Wallets)GetWallet(address string)Wallet  {
	return *ws.Wallets[address]
}

// 保存多个钱包
func (ws Wallets)SaveFile()  {
	var content bytes.Buffer

	gob.Register(elliptic.P256())

	encoder := gob.NewEncoder(&content)
	err := encoder.Encode(ws)
	if err != nil {
		log.Panic(err)
	}

/*
	func WriteFile(filename string, data []byte, perm os.FileMode) error
函数向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件，否则在写入数据之前清空文件。
*/
	err = ioutil.WriteFile(walletFile,content.Bytes(),0644)
	if err != nil {
		log.Panic(err)
	}
}
